#ifndef __WXD_UIELEMENT_H__
#define __WXD_UIELEMENT_H__

#include "defs.h"
#include <wx/list.h>

class WXDLLIMPEXP_FWD_DIRECTUI wxDUIElement;

WX_DECLARE_LIST(wxDUIElement, wxDUIElementList);

class WXDLLIMPEXP_DIRECTUI wxDUIElement : public wxObject
{
public:
	wxDUIElement();
	wxDUIElement(wxDUIElement* parent, 
		const wxString& id = wxEmptyString, 
		const wxPoint& position = wxDefaultPosition, 
		const wxSize& size = wxDefaultSize );
	virtual ~wxDUIElement();

	const wxString& GetId() const { return mId; }

	const wxPoint& GetPosition() const { return mPosition; }
	void SetPosition( const wxPoint& position ) { mPosition = position; }

	const wxSize& GetSize() const { return mSize; }
	void SetSize( const wxSize& size ) { mSize = size; }

	wxRect GetRect() const { return wxRect(mPosition, mSize); }
	void SetRect(const wxRect& rect) 
	{ 
		mPosition = rect.GetPosition();
		mSize = rect.GetSize();
	}

	virtual void AppendChild( wxDUIElement* element );
	virtual void PrependChild( wxDUIElement* element );
	virtual void InsertChild( int index, wxDUIElement* element );
	virtual bool RemoveChild( wxDUIElement* element );
	virtual wxDUIElement* RemoveChild( int index );
	virtual wxDUIElement* RemoveChild( const wxString& id );
	virtual void RemoveChildren();
	virtual bool DestoryChild( int index );
	virtual bool DestoryChild( const wxString& id );
	virtual void DestoryChildren();
	wxDUIElement* GetChild( int index ) const;
	wxDUIElement* GetChild( const wxString& id ) const;
	wxDUIElement* FindChild( const wxString& id) const;
	wxDUIElement* GetFirstChild() const;
	wxDUIElement* GetLastChild() const;
	int GetChildCount() const { return mChildren.GetCount(); }
	bool HasChild() const { return !mChildren.IsEmpty(); }
	const wxDUIElementList& GetChileren() const { return mChildren; }

	wxDUIElement* GetParent() const { return mParent; }
	wxDUIElement* GetGrandParent() const;
	wxDUIElement* GetRoot() const;
	wxDUIElement* GetPrevSibling() const { return mLeft; }
	wxDUIElement* GetNextSibling() const { return mRight; }

	const wxDUIElementList AsList() const;
	void AsList( wxDUIElementList& elelist) const;

	virtual bool IsShown() const { return mShown; }
	virtual void SetShown(bool enable = true) { mShown = enable; }

	virtual void Fit() = 0;
	virtual void Layout() = 0;

protected:
	virtual bool AllowAddChild( wxDUIElement* child ) const { return true; }
	virtual bool AllowRemoveChild( wxDUIElement* child ) const { return true; }

private:
	void SetNext( wxDUIElement* next) { mRight = next; }
	void SetPrev( wxDUIElement* prev) { mLeft = prev; }

	static void LinkElement( wxDUIElementList::compatibility_iterator node );
	static void UnlinkElement( wxDUIElementList::compatibility_iterator node );

public:
	class iterator
	{
	public:
		typedef iterator itor;
		typedef wxDUIElement* value_type;
		typedef value_type* ptr_type;
		typedef value_type& reference;
		typedef reference reference_type;
		typedef ptr_type pointer_type;

		wxDUIElement* mRoot;
		wxDUIElementList mEleList;
		wxDUIElementList::iterator mEleListItor;
	public:
		iterator() : mRoot(NULL) { mEleListItor = mEleList.begin(); }
		iterator( wxDUIElement* node ) : mRoot(node) 
		{ 
			mRoot->AsList(mEleList); 
			mEleListItor = mEleList.begin();
		}
	
		reference_type operator*() const
		{
			return *mEleListItor;
		}

		itor& operator++()
		{
			++mEleListItor;
			return *this;
		}
		const itor operator++(int)
		{
			mEleListItor++;
			return *this;
		}
		itor& operator--()
		{
			--mEleListItor;
			return *this;
		}
		const itor operator--(int)
		{
			mEleListItor--;
			return *this;
		}
		bool operator!=(const itor& it) const
		{
			return it.mEleListItor != mEleListItor;
		}
		bool operator==(const itor& it) const
		{
			return it.mEleListItor == mEleListItor;
		}
	};

protected:
	wxString mId;
	wxPoint mPosition;
	wxSize mSize;
	bool mShown;
	wxDUIElementList mChildren;
	wxDUIElement* mParent;
	wxDUIElement* mLeft;
	wxDUIElement* mRight;

private:
	DECLARE_ABSTRACT_CLASS(wxDUIElement);
};

#endif